// HSS.Net.Mail.SmtpClient.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       SmtpClient.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.Net.Mail
{
	#region Using Directives
	using System;
	using System.Text;
	using System.IO;
	using System.Net.Sockets;
	using System.Net;
	using System.Net.Mail;
	using System.Diagnostics;
	using System.Collections;
	using System.Collections.Generic;

	using HSS.IO;
	using HSS.Net.Dns;
	using HSS.Net.Dns.Records;
	using HSS.Logging;
	using System.Reflection;
	#endregion

	#region SmtpClient
	/// <summary>
	/// Provides methods to send email via smtp to a mail server
	/// </summary>
	public sealed class SmtpClient
	{
		#region Static API

		#region Constructor
		/// <summary>
		/// Static Constructor
		/// </summary>
		static SmtpClient()
		{
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets or sets the default HostName.
		/// </summary>
		public static string DefaultHostName
		{
			get;
			set;
		}
		/// <summary>
		/// Gets the current version of the HSS.Net.Mail SmtpClient
		/// </summary>
		public static string Version
		{
			get
			{
				if (string.IsNullOrEmpty(_version))
				{
					object[] attributes = typeof(HSS.Net.Mail.SmtpClient).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false);
					if (attributes.Length == 0)
						_version = typeof(HSS.Net.Mail.SmtpClient).Assembly.GetName().Version.ToString(4);
					else
						_version = ((AssemblyFileVersionAttribute)attributes[0]).Version;
				}
				return _version;
			}
		} static string _version;
		#endregion

		#region Methods
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <returns>true if the message was sent to all recipients successfully; otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public static bool TrySendEmail(MailMessage message)
		{
			bool success = true;
			try
			{
				var c = new SmtpClient();
				success = c.Send(message);
				c = null;
			}
			catch { success = false; }
			return success;
		}
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <param name="smtpServer">The SmtpServer that accepts emails for all recipients or will relay the message.</param>
		/// <returns>true if the message was sent to all recipients successfully; otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public static bool TrySendEmail(MailMessage message, string smtpServer)
		{
			bool success = true;
			try
			{
				var c = new SmtpClient();
				success = c.Send(message, smtpServer);
				c = null;
			}
			catch { success = false; }
			return success;
		}
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <param name="exception">The first unhandled exception; if any.</param>
		/// <returns>true if the message was sent to all recipients successfully and no errors where thrown; otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public static bool TrySendEmail(MailMessage message, out Exception exception)
		{
			bool success = true;
			exception = null;
			try
			{
				var c = new SmtpClient();
				success = c.Send(message);
				c = null;
			}
			catch (Exception ex)
			{
				exception = ex;
				success = false;
			}
			return success;
		}
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <param name="smtpServer">The SmtpServer that accepts emails for all recipients or will relay the message.</param>
		/// <param name="exception">The first unhandled exception; if any.</param>
		/// <returns>true if the message was sent to all recipients successfully and no errors where thrown; otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public static bool TrySendEmail(MailMessage message, string smtpServer, out Exception exception)
		{
			bool success = true;
			exception = null;
			try
			{
				var c = new SmtpClient();
				success = c.Send(message, smtpServer);
				c = null;
			}
			catch (Exception ex)
			{
				exception = ex;
				success = false;
			}
			return success;
		}
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <returns>The list of recipients that failed.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public static List<SmtpFailedRecipientException> SendEmail(MailMessage message)
		{
			var c = new SmtpClient();
			bool success = c.Send(message);
			var failedRecipients = c.failedRecipientExceptions;
			c = null;
			return failedRecipients;
		}
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <param name="smtpServer">The SmtpServer that accepts emails for all recipients or will relay the message.</param>
		/// <returns>The list of recipients that failed.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public static List<SmtpFailedRecipientException> SendEmail(MailMessage message, string smtpServer)
		{
			var c = new SmtpClient();
			c.Send(message, smtpServer);
			return c.failedRecipientExceptions;
		}
		/// <summary>
		/// Simple method for sending an email to one person.
		/// </summary>
		/// <param name="to">A single email address of where to deliver the message.</param>
		/// <param name="from">The address of who the email is from.</param>
		/// <param name="subject">The subject line.</param>
		/// <param name="body">The message body to send.</param>
		/// <param name="smtpServer">The SmtpServer that accepts emails for the TO: Email Address.</param>
		/// <exception cref="SmtpFailedRecipientsException">Failed to send to all recipients, the email was not delivered.</exception>
		/// <exception cref="SmtpFailedRecipientsException">Failed to send to some recipients.</exception>
		public static void SendEmail(string to, string from, string subject, string body, string smtpServer)
		{
			var c = new SmtpClient();
			c.QuickSend(to, from, subject, body, smtpServer);
		}
		/// <summary>
		/// Create an valid SMTP TimeStamp.
		/// </summary>
		/// <param name="value">The DateTime to convert.</param>
		/// <returns>The valid SMTP TimeStamp.</returns>
		internal static string GetDateTimeString(DateTime value)
		{
			string[] months = new string[13];
			months[1] = "Jan";
			months[2] = "Feb";
			months[3] = "Mar";
			months[4] = "Apr";
			months[5] = "May";
			months[6] = "Jun";
			months[7] = "Jul";
			months[8] = "Aug";
			months[9] = "Sep";
			months[10] = "Oct";
			months[11] = "Nov";
			months[12] = "Dec";

			StringBuilder dateBuilder = new StringBuilder();
			dateBuilder.Append(value.Day);
			dateBuilder.Append(' ');
			dateBuilder.Append(months[value.Month]);
			dateBuilder.Append(' ');
			dateBuilder.Append(value.Year);
			dateBuilder.Append(' ');
			if (value.Hour <= 9)
			{
				dateBuilder.Append('0');
			}
			dateBuilder.Append(value.Hour);
			dateBuilder.Append(':');
			if (value.Minute <= 9)
			{
				dateBuilder.Append('0');
			}
			dateBuilder.Append(value.Minute);
			dateBuilder.Append(':');
			if (value.Second <= 9)
			{
				dateBuilder.Append('0');
			}
			dateBuilder.Append(value.Second);
			string text1 = TimeZone.CurrentTimeZone.GetUtcOffset(value).ToString();
			if (text1[0] != '-')
			{
				dateBuilder.Append(" +");
			}
			else
			{
				dateBuilder.Append(" ");
			}
			string[] textArray2 = text1.Split(new char[] { ':' });

			dateBuilder.Append(textArray2[0]);
			dateBuilder.Append(textArray2[1]);

			return dateBuilder.ToString();

		}
		#endregion

		#endregion

		#region Instance API

		#region Fields

		private string currentDomain = string.Empty;
		#endregion

		#region Constructor
		/// <summary>
		/// Constructor
		/// </summary>
		public SmtpClient()
		{
			failedRecipientExceptions = new List<SmtpFailedRecipientException>();
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the list of recipients that failed.
		/// </summary>
		public List<SmtpFailedRecipientException> FailedRecipientExceptions
		{
			get { return failedRecipientExceptions; }
		} List<SmtpFailedRecipientException> failedRecipientExceptions;
		#endregion

		#region Methods

		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <returns>true if the message was sent to all recipients successfully; otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public bool Send(MailMessage message)
		{
			if (null == message)
				throw new ArgumentNullException("Message");

			this.failedRecipientExceptions.Clear();

			string[] smtpServer = null;
			List<Domain> domains = new List<Domain>();
			EmailAddress ea = new EmailAddress();
			string data = string.Empty;
			int submittedRecipientCount = 0;

			#region Lookup Smtp Servers

			#region TO:
			if (null != message.To && message.To.Count > 0)
			{
				foreach (MailAddress s in message.To)
				{
					submittedRecipientCount++;
					ea = new EmailAddress(s.Address);
					if (ea.IsValid)
					{
						currentDomain = ea.Domain;
						if (!domains.Exists(this.DomainNamePredicate))
						{
							if (this.SmtpLookup(ea, out smtpServer))
							{
								Domain newDomain = new Domain(currentDomain, smtpServer);
								newDomain.To.Add(ea);
								domains.Add(newDomain);
							}
						}
						else
						{
							Domain dfound = domains.Find(this.DomainNamePredicate);
							if (null != dfound)
								dfound.To.Add(ea);
						}
					}
				}
			}
			#endregion

			#region CC:
			if (null != message.CC && message.CC.Count > 0)
			{
				foreach (MailAddress s in message.CC)
				{
					submittedRecipientCount++;
					ea = new EmailAddress(s.Address);
					if (ea.IsValid)
					{
						currentDomain = ea.Domain;
						if (!domains.Exists(this.DomainNamePredicate))
						{
							if (this.SmtpLookup(ea, out smtpServer))
							{
								Domain newDomain = new Domain(currentDomain, smtpServer);
								newDomain.Cc.Add(ea);
								domains.Add(newDomain);
							}
						}
						else
						{
							Domain dfound = domains.Find(this.DomainNamePredicate);
							if (null != dfound)
								dfound.Cc.Add(ea);
						}
					}
				}
			}
			#endregion

			#region BCC:
			if (null != message.Bcc && message.Bcc.Count > 0)
			{
				foreach (MailAddress s in message.Bcc)
				{
					submittedRecipientCount++;
					ea = new EmailAddress(s.Address);
					if (ea.IsValid)
					{
						currentDomain = ea.Domain;
						if (!domains.Exists(this.DomainNamePredicate))
						{
							if (this.SmtpLookup(ea, out smtpServer))
							{
								Domain newDomain = new Domain(currentDomain, smtpServer);
								newDomain.Bcc.Add(ea);
								domains.Add(newDomain);
							}
						}
						else
						{
							Domain dfound = domains.Find(this.DomainNamePredicate);
							if (null != dfound)
								dfound.Bcc.Add(ea);
						}
					}
				}
			}
			#endregion

			// Ensure we have at least one recipient
			if (domains.Count == 0)
			{
				if (submittedRecipientCount == 0)
					throw new InvalidOperationException(HSS.Net.Mail.Resources.SmtpRecipientRequired);
				else
					throw new InvalidOperationException(HSS.Net.Mail.Resources.SmtpInvalidRecipients);
			}

			#endregion

			#region Create the Message Body
			data = this.CreateEmailData(message);
			#endregion

			#region Send for each Domain
			foreach (Domain domain in domains)
			{
				#region Recipients

				MailAddressCollection recipients = new MailAddressCollection();

				#region TO:
				if (null != domain.To && domain.To.Count > 0)
				{
					foreach (EmailAddress address in domain.To)
					{
						recipients.Add(address.Mailbox);
					}
				}
				#endregion

				#region CC:
				if (null != domain.Cc && domain.Cc.Count > 0)
				{
					foreach (EmailAddress address in domain.Cc)
					{
						recipients.Add(address.Mailbox);
					}
				}
				#endregion

				#region BCC:
				if (null != domain.Bcc && domain.Bcc.Count > 0)
				{
					foreach (EmailAddress address in domain.Bcc)
					{
						recipients.Add(address.Mailbox);
					}
				}
				#endregion

				#endregion

				if (recipients.Count > 0)
					SendInternal((message.Sender != null) ? message.Sender : message.From, recipients, data, domain.SmtpServer);
			}
			#endregion

			return this.failedRecipientExceptions.Count == 0;
		}
		/// <summary>
		/// Sends an email using Smtp.
		/// </summary>
		/// <param name="message">The <see cref="MailMessage"/> to send.</param>
		/// <param name="smtpServer">The SmtpServer that accepts emails for all recipients or will relay the message.</param>
		/// <returns>true if the message was sent to all recipients successfully; otherwise false.</returns>
		/// <exception cref="ArgumentNullException">Message parameter cannot be null.</exception>
		/// <exception cref="InvalidOperationException">At least one recipient must be specified.</exception>
		public bool Send(MailMessage message, string smtpServer)
		{
			if (null == message)
				throw new ArgumentNullException("Message");

			this.failedRecipientExceptions.Clear();

			var recipients = new MailAddressCollection();
			var submittedRecipientCount = this.GetRecipientsList(message, recipients);
			if (recipients.Count == 0)
			{
				if (submittedRecipientCount == 0)
					throw new InvalidOperationException(HSS.Net.Mail.Resources.SmtpRecipientRequired);
				else
					throw new InvalidOperationException(HSS.Net.Mail.Resources.SmtpInvalidRecipients);
			}

			var data = this.CreateEmailData(message);
			this.SendInternal((message.Sender != null) ? message.Sender : message.From, recipients, data, new string[] { smtpServer });

			return this.failedRecipientExceptions.Count == 0;
		}
		/// <summary>
		/// Simple method for sending an email to one person.
		/// </summary>
		/// <param name="to">A single email address of where to deliver the message.</param>
		/// <param name="from">The address of who the email is from.</param>
		/// <param name="subject">The subject line.</param>
		/// <param name="body">The message body to send.</param>
		/// <param name="smtpServer">The SmtpServer that accepts emails for the TO: Email Address.</param>
		/// <exception cref="SmtpFailedRecipientsException">Failed to send to all recipients, the email was not delivered.</exception>
		/// <exception cref="SmtpFailedRecipientsException">Failed to send to some recipients.</exception>
		public void QuickSend(string to, string from, string subject, string body, string smtpServer)
		{
			this.failedRecipientExceptions.Clear();

			MailMessage message = new MailMessage();
			message.To.Add(to);
			message.From = new MailAddress(from);
			message.Subject = subject;
			message.Body = body;
			string data = this.CreateEmailData(message);

			SendInternal(message.From, message.To, data, new string[] { smtpServer });

			if (this.failedRecipientExceptions.Count > 0)
			{
				if (this.failedRecipientExceptions.Count == (message.To.Count + message.CC.Count + message.Bcc.Count))
				{
					string errMsg = "Failed to send to all recipients, the email was not delivered.";
					throw new SmtpFailedRecipientsException(errMsg, this.failedRecipientExceptions.ToArray());
				}
				else
				{
					string errMsg = "Failed to send to some recipients.";
					throw new SmtpFailedRecipientsException(errMsg, this.failedRecipientExceptions.ToArray());
				}
			}
		}
		/// <summary>
		/// Using the given Email Address, Queries for a preferred SmtpServer using a Dns Query
		/// </summary>
		/// <param name="mailBox">The MailBox to query for</param>
		/// <param name="smtpServers">The SmtpServers for the Email Address provided</param>
		/// <returns>true if an SmtpServer was found; otherwise false</returns>
		public bool SmtpLookup(EmailAddress mailBox, out string[] smtpServers)
		{
			// Default to null
			smtpServers = null;

			// Must have a valid email address
			if (!mailBox.IsValid)
				return false;

			// Query for Smtp Servers
			Response response = DnsClient.Query(mailBox.Domain, QType.MX, QClass.IN, true);
			List<AnswerRR> resources = response.Answers;

			if (resources.Count > 0)
			{
				smtpServers = new string[resources.Count];

				for (int i = 0; i < resources.Count; i++)
				{
					if (resources[i].Type == HSS.Net.Dns.Type.MX)
					{
						smtpServers[i] = ((RecordMX)resources[i].RECORD).EXCHANGE;
						Console.WriteLine("Smtp [ " + smtpServers[i] + " ] Preference: {0}", ((RecordMX)resources[i].RECORD).PREFERENCE);
					}
				}

				return true;
			}
			else
			{
				return false;
			}
		}
		/// <summary>
		/// Verifies the Smtp Server receives email for the MailBox
		/// </summary>
		/// <param name="smtpServer">The Smtp Server</param>
		/// <param name="mailBox">The MailBox to validate</param>
		/// <param name="ex">Contains any failed recipient errors encountered during the send operation</param>
		/// <returns>true if the Smtp Server accepts email for the MailBox; otherwise false</returns>
		public bool ValidateEmailSmtp(string smtpServer, string mailBox, out SmtpFailedRecipientException ex)
		{
			string[] smtpServers = new string[] { smtpServer };
			ex = null;

			this.failedRecipientExceptions.Clear();

			MailAddressCollection recipients = new MailAddressCollection();
			recipients.Add(new MailAddress(mailBox));

			this.SendInternal(new MailAddress("smtptest@localhost.com"), recipients, string.Empty, smtpServers);

			if (this.failedRecipientExceptions.Count > 0)
				ex = this.failedRecipientExceptions[0];

			return null == ex;
		}

		private int GetRecipientsList(MailMessage message, MailAddressCollection recipients)
		{
			int submittedRecipientCount = 0;

			#region TO:
			if (null != message.To && message.To.Count > 0)
			{
				foreach (var to in message.To)
				{
					submittedRecipientCount++;
					recipients.Add(to);
				}
			}
			#endregion

			#region CC:
			if (null != message.CC && message.CC.Count > 0)
			{
				foreach (var cc in message.CC)
				{
					submittedRecipientCount++;
					recipients.Add(cc);
				}
			}
			#endregion

			#region BCC:
			if (null != message.Bcc && message.Bcc.Count > 0)
			{
				foreach (var bcc in message.Bcc)
				{
					submittedRecipientCount++;
					recipients.Add(bcc);
				}
			}
			#endregion

			return submittedRecipientCount;
		}
		private string CreateEmailData(MailMessage message)
		{
			StringBuilder body = new StringBuilder();

			#region Headers

			#region From, Reply-To, Sender
			if (null != message.From && !string.IsNullOrEmpty(message.From.Address))
			{
				body.Append("From: " + FormatMailAddress(message.From) + "\r\n");
			}
			if (null != message.ReplyToList && message.ReplyToList.Count > 0)
			{
				body.Append("Reply-To: " + FormatMailAddress(message.ReplyToList[0]) + "\r\n");
			}
			if (null != message.Sender && !string.IsNullOrEmpty(message.Sender.Address))
			{
				body.Append("Sender: " + message.Sender + "\r\n");
			}
			#endregion

			#region To
			if (null != message.To && message.To.Count > 0)
			{
				body.Append("To: ");
				for (int i = 0; i < message.To.Count; i++)
				{
					body.Append(i > 0 ? "," : "");
					body.Append(FormatMailAddress(message.To[i]));
				}
				body.Append("\r\n");
			}
			#endregion

			#region Cc
			if (null != message.CC && message.CC.Count > 0)
			{
				body.Append("Cc: ");
				for (int i = 0; i < message.CC.Count; i++)
				{
					body.Append(i > 0 ? "," : "");
					body.Append(FormatMailAddress(message.CC[i]));
				}
				body.Append("\r\n");
			}
			#endregion

			#region Bcc
			if (null != message.Bcc && message.Bcc.Count > 0)
			{
				body.Append("Bcc: ");
				body.Append("\r\n");
			}
			#endregion

			body.Append("Date: " + GetDateTimeString(DateTime.Now) + "\r\n");
			body.Append("Subject: " + message.Subject + "\r\n");

			if (null != message.From && !string.IsNullOrEmpty(message.From.Address))
			{
				body.Append("X-Sender: " + FormatMailAddress(message.From) + "\r\n");
			}
			if (message.Priority == MailPriority.High)
			{
				body.Append("X-Priority: 1" + "\r\n");
				body.Append("Priority: Urgent" + "\r\n");
				body.Append("Importance: high" + "\r\n");
			}
			else if (message.Priority == MailPriority.Low)
			{
				body.Append("X-Priority: 5" + "\r\n");
				body.Append("Priority: Non-Urgent" + "\r\n");
				body.Append("Importance: low" + "\r\n");
			}

			foreach (string headerEntry in message.Headers)
			{
				if (!string.IsNullOrEmpty(headerEntry))
				{
					string headerValue = message.Headers[headerEntry];
					string entry = headerEntry.ToLower();

					if (!string.IsNullOrEmpty(headerValue)
						&& entry != "reply-to"
						&& entry != "sender"
						&& entry != "priority"
						&& entry != "importance"
						&& entry != "x-sender"
						&& entry != "x-mailer"
						&& entry != "x-priority")
						body.Append(string.Format("{0}: {1}\r\n", headerEntry, headerValue));
				}
			}

			body.Append("X-Mailer: HSS.Net.Mail.SmtpClient v" + SmtpClient.Version + "\r\n");

			#endregion

			#region Body

			string boundary = GetBoundary();
			body.Append("MIME-Version: 1.0\r\n");
			body.Append("Content-Type: multipart/mixed;");
			body.AppendFormat("boundary=\"{0}\"\r\n", boundary);
			body.Append("\r\n");

			#region MimeData

			StringBuilder mimeData = new StringBuilder();

			#region Message
			if (!string.IsNullOrEmpty(message.Body))
			{
				mimeData.AppendFormat("--{0}\r\n", boundary);
				if (message.IsBodyHtml)
				{
					mimeData.Append("Content-Type: text/html; " + message.BodyEncoding.HeaderName + "\r\n");
					mimeData.Append("Content-Transfer-Encoding: 7Bit\r\n");
					mimeData.Append("\r\n");
					mimeData.Append(message.Body + "\r\n");
					mimeData.Append("\r\n");
				}
				else
				{
					mimeData.Append("Content-Type: text/plain; " + message.BodyEncoding.HeaderName + "\r\n");
					mimeData.Append("Content-Transfer-Encoding: 7Bit\r\n");
					mimeData.Append("\r\n");
					mimeData.Append(message.Body + "\r\n");
					mimeData.Append("\r\n");
				}
			}
			#endregion

			#region Attachments
			foreach (Attachment att in message.Attachments)
			{
				byte[] binaryData;
				long bytesRead;
				if (att != null && att.ContentStream.Length > 0)
				{
					#region Append Attachment

					mimeData.AppendFormat("--{0}\r\n", boundary);

					if (!string.IsNullOrEmpty(att.ContentId))
						mimeData.Append("Content-Id: " + att.ContentId + "\r\n");

					if (string.IsNullOrEmpty(att.ContentType.Name))
						mimeData.Append("Content-Type: " + att.ContentType.MediaType + "\r\n");
					else
						mimeData.Append("Content-Type: " + att.ContentType.MediaType + "; name=" + att.ContentType.Name + "\r\n");

					if (!string.IsNullOrEmpty(att.ContentDisposition.FileName))
					{
						string fname = att.ContentDisposition.FileName;
						mimeData.Append("Content-Description: " + fname + "\r\n");
						mimeData.Append("Content-Disposition: " + att.ContentDisposition.DispositionType + "; filename=" + fname + "\r\n");
					}
					else
					{
						mimeData.Append("Content-Disposition: " + att.ContentDisposition.DispositionType + "\r\n");
					}

					// We only supports base64
					mimeData.Append("Content-Transfer-Encoding: base64\r\n");
					mimeData.Append("\r\n");
					binaryData = new Byte[att.ContentStream.Length];
					bytesRead = att.ContentStream.Read(binaryData, 0, (int)att.ContentStream.Length);
					string base64String = System.Convert.ToBase64String(binaryData, 0, binaryData.Length, Base64FormattingOptions.InsertLineBreaks);
					mimeData.Append(base64String);
					mimeData.Append("\r\n");

					#endregion
				}
			}
			#endregion

			mimeData.AppendFormat("--{0}--\r\n", boundary);
			body.Append(mimeData.ToString());

			#endregion

			#endregion

			return body.ToString();

		}
		private string FormatMailAddress(MailAddress address)
		{
			string formattedAddress = string.Empty;
			if (address.DisplayName.Length > 0)
			{
				formattedAddress = address.DisplayName;
				formattedAddress += " <" + address.Address + ">";
			}
			else
			{
				formattedAddress = "<" + address.Address + ">";
			}
			return formattedAddress;
		}
		private bool DomainNamePredicate(Domain domain)
		{
			return domain.DomainName == currentDomain;
		}
		private string GetBoundary()
		{
			Random randObj = new Random((int)DateTime.Now.Ticks);
			string boundary = "__=_Part_Boundary_" + randObj.Next().ToString() + "_" + randObj.Next().ToString();
			return boundary;
		}

		private void SendInternal(MailAddress sender, MailAddressCollection recipients, string data, string[] smtpServers)
		{
			if (smtpServers.Length == 0)
				throw new SmtpException("Must have at least one Smtp Server.");

			using (SmtpConnection smtpConn = new SmtpConnection(smtpServers))
			{

				// Initiate communication with server - Extended Hello
				EHelloCommand.Send(smtpConn);

				// Mail FROM:
				MailCommand.Send(smtpConn, sender);

				// Recipients TO:
				this.failedRecipientExceptions.Clear();
				bool inError = false;
				foreach (MailAddress address in recipients)
				{
					SmtpStatusCode serverResponseCode = SmtpStatusCode.Ok;
					string serverResponse = string.Empty;

					if (inError)
					{
						// Record a failed recipient
						this.failedRecipientExceptions.Add(
							new SmtpFailedRecipientException(serverResponseCode, address.Address, serverResponse));
						continue;
					}

					if (!RecipientCommand.Send(smtpConn, address, out serverResponseCode, out serverResponse))
					{
						// Record a failed recipient
						this.failedRecipientExceptions.Add(
							new SmtpFailedRecipientException(serverResponseCode, address.Address, serverResponse));

						// Validate connection is still available, if not throw Recipient Failed Status Code
						if (smtpConn.StatusCode != SmtpStatusCode.ServiceReady)
						{
							#region Log Connection Exceptions
							try
							{
								if (serverResponseCode != smtpConn.StatusCode)
								{
									inError = true;
									SmtpException ex2 = new SmtpException(serverResponseCode);
									string err = ex2.Message + Environment.NewLine;
									ex2 = new SmtpException(smtpConn.StatusCode);
									err += ex2.Message;
									Log.WriteException(new SmtpException(err));
									break;
								}
							}
							catch { }
							#endregion
						}
					}
				}

				// If all recipients failed, then go ahead and bail out, otherwise send to who we can.
				if (this.failedRecipientExceptions.Count == recipients.Count)
					return;

				// Send DATA
				if (data.Length > 0)
					DataCommand.Send(smtpConn, data);
			}
		}

		#endregion

		#endregion
	}
	#endregion
}